在 Workbox 详解篇:预缓存中,我们简单介绍了 workbox-webpack-plugin,本章我们将深入介绍 workbox-webpack-plugin 的底层依赖 workbox-build,通过该模块,我们可以:
- 根据配置,直接生成 Service Worker 脚本;
- 根据配置,生成预缓存列表,并将其附加到已有的 Service Worker 脚本中。
- 接下来,我们将一起探讨 workbox-build 的使用细节。
# generateSW
const { generateSW } = require('workbox-build');
generateSW({
//... 其他配置
swDest: 'public/sw.js',
globDirectory: '.'
}).then(({ count, size, warnings }) => {
//...doSomething
});
示例中,我们通过
workbox-build中的generateSW方法来生成 Service Worker 脚本,该方法的返回值为Promise<GenerateSWResult>,其中 GenerateSWResult 为含有以下属性的对象:
count:预缓存列表中的文件个数。size:预缓存文件的总尺寸大小,单位为byte。warnings:构建过程中所产生的警告信息,类型为字符串数组。
该方法的配置属性为:
swDest:将要生成 Service Worker 脚本的路径及文件名,如果值为相对路径,那么:- 如果运行在 node 环境中,路径相对于当前的工作目录。
- 如果运行在 webpack 环境中,路径相对于 output 配置中的 path 属性。
importWorkboxFrom:Workbox入口文件 workbox-sw.js 的加载路径,可选值为:cdn:默认值,将从Google Cloud Storage中加载 workbox-sw.js,由于国内网络问题,一般不使用该选项。local:如使用该选项,在构建过程中会将 Workbox 模块代码拷贝到构建目录中,并从该目录中加载workbox-sw.js。disabled:如使用该选项,Service Worker 脚本将不会包含加载workbox-sw.js的代码。
skipWaiting:是否在install事件中调用skipWaiting方法(Boolean类型,默认值为false),如果该属性的值为false,Service Worker 脚本将包含以下代码:
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
clientsClaim:是否在activate事件中调用clients.claim方法(Boolean 类型,默认值为 false)。runtimeCaching:运行时缓存配置,类型为对象数组(默认值为[]),其中每一项包含以下属性:urlPatterns:请求匹配规则,类型为字符串、正则表达式或函数,其中:- 值为函数时,用法等同于 Workbox 详解篇:路由设置中
workbox.routing.registerRoute方法的capture参数。
- 值为函数时,用法等同于 Workbox 详解篇:路由设置中
handler:请求处理,类型为字符串或函数,其中:- 值为字符串时,其值必须为
CacheFirst、CacheOnly、NetworkFirst、NetworkOnly或StaleWhileRevalidate。 - 值为函数时,用法等同于
Workbox详解篇:路由设置中workbox.routing.registerRoute方法的handler参数
- 值为字符串时,其值必须为
method:请求方法,值为GET、HEAD、POST、PATCH、PUT或DELETE,默认值为GET。options:handler为字符串时的配置参数,主要属性有:cacheName:缓存名称,默认值为 Workbox 配置中的运行时缓存名。fetchOptions:网络请求配置信息,结构与函数 fetch 中的 init 参数一致(在 CacheOnly 中,该属性将会被忽略)。matchOptions:CacheQueryOptions 对象(在 NetworkOnly 中,该属性将会被忽略)。networkTimeoutSeconds:如果对该属性进行了赋值,那么网络会在指定的时间内没有响应时使用本地缓存来进行响应(该属性仅在 NetworkFirst 中有效)。expiration:插件workbox.expiration.Plugin配置信息,详情参见:Workbox 详解篇:请求策略 & 缓存置换策略相关内容。backgroundSync:插件workbox.backgroundSync.Plugin配置信息,详情参见:Workbox 详解篇:后台同步相关内容。cacheableResponse:插件workbox.cacheableResponse.Plugin配置信息,详情参见:Workbox 详解篇:可缓存对象相关内容。broadcastUpdate:插件workbox.broadcastUpdate.Plugin配置信息,详情参见:Workbox 详解篇:缓存更新广播相关内容。- `plugins:自定义插件列表,自定义插件详情参见:Workbox 详解篇:插件相关内容。
navigateFallback:使用该属性的值作为键值,从预缓存中获取指定资源来响应所有的导航请求。navigateFallbackBlacklist:正则表达式数组,作用等同于workbox.routing.registerNavigationRoute的blacklist属性。navigateFallbackWhitelist:正则表达式数组,作用等同于workbox.routing.registerNavigationRoute的whitelist属性。importScripts:需要加载的脚本列表。ignoreURLParametersMatching:预缓存配置,用于忽略请求中符合指定规则的查询参数,详情参见:Workbox 详解篇:预缓存相关内容。directoryIndex:预缓存配置,默认值为 index.html,即以预缓存/index.html来响应 / 的请求。cacheId:用于设置缓存名配置中的 prefix 属性。offlineGoogleAnalytics:是否启用离线Google Analytics(Boolean 类型,默认值为 false)。cleanupOutdatedCaches:是否添加workbox.precaching.cleanupOutdatedCaches()调用来清理过期的预缓存项目(Boolean 类型,默认值为 false)。navigationPreload:是否开启导航预加载(Boolean 类型,默认值为 false),当值为 true 时,需设置runtimeCaching对导航请求进行处理,且必须消费event.preloadResponse。globPatterns:能够被加入到预缓存列表的文件匹配模式,类型为字符串模式数组,默认值- 在
workbox-build和workbox-cli下为['**/*.{js,css,html}']。 - 在
workbox-webpack-plugin下为[]。
- 在
globDirectory:文件遍历的起始目录,如果值为相对路径,则相对于当前工作目录,如设置了该属性,除非设置了templatedURLs属性,否则需同时设置 globPatterns 属性。globFollow:文件匹配时,是否遵循符号链接规则(Boolean 类型,默认值为 true)。globIgnores:文件匹配时,需要排除的文件匹配规则列表,默认值为['node_modules/**/*']。globStrict:文件匹配时,如果目录读取的过程中出现异常,如果值为 true 将抛出异常并终止构建进程,否则将忽略该目录,默认值为 true。templatedURLs:默认情况下,加入到预缓存列表中每一项 revision 的值为文件的 hash 值,我们可通过该属性改变此默认行为。类型为对象,其中,每一项的键为文件的网络路径,值为:- 为字符串时,直接将该字符串的 hash 值作为预缓存文件的 revision 值。
- 为字符串数组时,将被当作
globPatterns进行文件匹配,将匹配到所有文件的总 hash 值作为预缓存文件的 revision 值。
maximumFileSizeToCacheInBytes:当文件尺寸大于指定大小时,将不会将其加入到预缓存列表中(单位为 byte,默认值为2097152)。dontCacheBustURLsMatching:类型为正则表达式,默认为空,当文件名符合指定规则时,在将其加入预缓存列表中将不会为该文件设置 revision 值。modifyURLPrefix:修改预缓存列表中每一项 url 值的前缀,类型为对象,比如:
self.__precacheManifest = [
{
"url": "/dist/main.js",
"revision": "0d12a38a0f7f730d93c6ff98082c6d99"
}
].concat(self.__precacheManifest || []);
如果 modifyURLPrefix 配置如下:
modifyURLPrefix: {
'/dist': ''
}
那么上述预缓存列表将被替换成:
self.__precacheManifest = [
{
"url": "/main.js",
"revision": "0d12a38a0f7f730d93c6ff98082c6d99"
}
].concat(self.__precacheManifest || []);
manifestTransforms:通过该属性,可以对预缓存列表进行自定义转换,类型为函数数组,函数签名为(Array<ManifestEntry>) => ManifestTransformResult:ManifestEntry为含有以下属性的对象:url:文件地址,类型为字符串。revision:文件 hash 值,类型为字符串。
ManifestTransformResult为含有以下属性的对象:manifest:文件列表,类型为ManifestEntry数组。warnings:警告信息列表,类型为字符串数组。
如果同时设置了 dontCacheBustURLsMatching或 modifyURLPrefix 属性,那么该属性将在它们两个之后执行。
除了通过 generateSW 方法快速生成 Service Worker 脚本外,我们也可通过 generateSWSring 方法来生成 Service Worker 脚本的字符串,使用方法如下:
const { generateSWString } = require('workbox-build');
generateSWString({
//... 其他配置
globDirectory: '.',
}).then(({ swString, warnings }) => {
//...doSomething
});
该方法的返回值为 Promise<GenerateSWStringResult>,其中 GenerateSWStringResult 为含有以下属性的对象:
swString:生成的脚本字符串。warnings:构建过程中所产生的警告信息,类型为字符串数组。
该方法的配置属性除了没有 swDest 外,其他的与 generateSW 完全相同,此处不再重述。
# injectManifest
当需要添加较为复杂(比如:推送通知)的逻辑时,generateSW 或 generateSWString 方法已不能满足我们的需求,此时,可使用 injectManifest 方法来帮助生成预缓存列表,并将其与我们自己实现的 Service Worker 脚本进行合并,使用方法如下:
const { injectManifest } = require('workbox-build');
injectManifest({
//... 其他配置
swSrc: 'src/sw.js',
swDest: 'public/sw.js',
globDirectory: '.'
}).then(({ count, size, warnings }) => {
//...doSomething
});
该方法的返回值等同于 generateSW 方法的返回值,此处不再重述。其配置属性主要有:
- swSrc:包含自定义逻辑的 Service Worker 脚本的路径及文件名,如值为相对路径,则相对于当前工作目录,并且需要注意的是:
- 在 node 环境中,脚本中需要包含以下代码:
workbox.precaching.precacheAndRoute([]); - 在 webpack 环境中,脚本中需要包含以下代码:
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
- 在 node 环境中,脚本中需要包含以下代码:
- swDest、globDirectory、globFollow、globIgnores、globPatterns、globStrict、templatedURLs、maximumFileSizeToCacheInBytes、dontCacheBustURLsMatching、modifyURLPrefix 及 manifestTransforms 等同于 generateSW 方法的相关属性,此处不再重述
同 generateSWString 一样,我们亦可通过 getManifest 方法来获取预缓存列表,使用方法如下:
const { getManifest } = require('workbox-build');
getManifest({
//... 其他配置
globDirectory: '.'
}).then(({ manifestEntries, count, size, warnings }) => {
//...doSomething
});
该方法的返回值为
Promise<GetManifestResult>,其中 GetManifestResult 为含有以下属性的对象:
manifestEntries:预缓存资源列表,类型为Array<ManifestEntry>,ManifestEntry 已在上文中作过说明,此处不再重述。count:预缓存列表中的文件个数。size:预缓存文件的总尺寸大小,单位为 byte。warnings:构建过程中所产生的警告信息,类型为字符串数组。 该方法的配置属性除了没有 swSrc、swDest 外,其他的与injectManifest完全相同,此处不再重述。
# workbox-webpack-plugin
虽然 workbox-webpack-plugin 底层使用了 workbox-build,但在使用的过程中,依旧需要注意以下两点:
- 如果某一 chunk 中包含 workbox-sw 模块的代码,那么亦可将该 chunk 的名称作为 importWorkboxFrom 属性的值。
- 一般情况下,无需配置
globPatterns、globDirectory、globFollow、globIgnores、globStrict、templatedURLs、maximumFileSizeToCacheInBytes、dontCacheBustURLsMatching和modifyURLPrefix属性,这是因为workbox-webpack-plugin会自动将webpack 打包编译的资源加入到预缓存列表中。这些属性仅用于将不能被 webpack 识别的资源添加到 预缓存列表 中,且maximumFileSizeToCacheInBytes、dontCacheBustURLsMatching和modifyURLPrefix对 webpack 打包编译的资源无效。
相对于
workbox-build,workbox-webpack-plugin中的GenerateSW及 InjectManifest 新增了以下配置选项:
- chunks:默认情况下,插件会将所有 chunk 下的资源加入到预缓存列表中,如果只想将指定 chunk 下的资源加入到预缓存列表中,可通过配置该选项实现(类型为字符串数组,每一项为 chunk 名称,默认值为 [])。
excludeChunks:与 chunks 的作用相反,如果配置了该选项,那么设置中指定的 chunk 下的资源将不会被加入到预缓存列表中(类型为字符串数组,每一项为 chunk 名称,默认值为 [])。include:如果配置了该选项,插件便会只将满足指定规则的资源加入到预缓存列表中(类型为字符串或正则表达式数组),该选项在chunks、excludeChunks之后执行。exclude:与include的作用相反,插件只将不满足指定规则的资源加入到预缓存列表中(类型为字符串或正则表达式数组,默认值为[/\.map$/, /^manifest.*\.js$/]),该选项在chunks、excludeChunks之后执行。importsDirectory:默认情况下,插件会将自动生成的包含预缓存列表信息的脚本文件、Workbox 模块代码(importWorkboxFrom 的值为 local 时才会拷贝)放置到 webpack output 配置中 path 属性所指定的顶层目录下,如果设置了该选项,插件会在顶层目录下创建指定目录,并将前面所述文件放置到该目录下。precacheManifestFilename:插件会自动生成包含预缓存列表信息的脚本文件,该文件的默认名称为precache-manifest.[manifestHash].js,可通过该选项修改其默认名称,但名称中必须包含[manifestHash]。
# 总结
本章我们首先对 workbox-build 进行了详细介绍,然后讨论了 workbox-webpack-plugin 与 workbox-build 的差异。通过这些模块,我们既可以直接生成 Service Worker 脚本来满足简单需求,也可通过生成预缓存列表并与现有 Service Worker 脚本合并的方式来满足复杂需求。至此我们已完成了 Workbox 系列整个核心部分的学习,相信到此我们已经掌握了:
- 如何使用
workbox.precaching.precacheAndRoute或workbox.precaching.PrecacheController进行预缓存处理。 - 如何使用
workbox.routing.registerRoute或workbox.routing.DefaultRouter进行运行时路由设置。 - 如何使用
workbox.strategies.*及workbox.expiration.Plugin来处理请求策略及缓存置换问题。 - 如何在 Workbox 处理导航预加载及后台同步问题。
- Workbox 中可缓存对象、缓存更新广播及插件的使用。
- 如何通过 Workbox Window 对象来轻松管理 Service Worker 的注册、更新及通信。
- 如何使用 workbox-build 及
workbox-webpack-plugin与现代 Web 构建工具结合来轻松管理 Service Worker 脚本。